package by.amakarevich.dataaccess.Impl;

import java.util.List;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.SingularAttribute;

import org.hibernate.jpa.criteria.OrderImpl;
import org.springframework.stereotype.Repository;

import by.amakarevich.dataaccess.ProductDao;
import by.amakarevich.datamodel.Product;
import by.amakarevich.datamodel.Product_;
import by.amakarevich.datamodel.enums.Category;

@Repository
public class ProductDaoImpl extends AbstractDaoImpl<Long, Product> implements ProductDao {

	protected ProductDaoImpl() {
		super(Product.class);
	}
	
	@Override
    public List<Product> getAllProductsByCompany(String company, Category category) {
        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Product> root = cBuilder.createQuery(Product.class);
        Root<Product> criteria = root.from(Product.class);

        root.select(criteria);

        root.where(cBuilder.and(cBuilder.equal(criteria.get(Product_.company), company)),
        		cBuilder.equal(criteria.get(Product_.category), category));

        TypedQuery<Product> query = getEm().createQuery(root);
        List<Product> results = query.getResultList();
        return results;
    }
	
	@Override
    public List<Product> getAllProductsByCategory(Category category) {
        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Product> root = cBuilder.createQuery(Product.class);
        Root<Product> criteria = root.from(Product.class);

        root.select(criteria);

        root.where(cBuilder.equal(criteria.get(Product_.category), category));

        TypedQuery<Product> query = getEm().createQuery(root);
        List<Product> results = query.getResultList();
        return results;
    }
	
	@Override
    public List<Product> getSortedAllProduct(SingularAttribute<Product, ?> attr, boolean ascending, int startRecord, int pageSize, Category category) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Product> criteria = cBuilder.createQuery(Product.class);
        Root<Product> root = criteria.from(Product.class);

        criteria.select(root);
        criteria.orderBy(new OrderImpl(root.get(attr), ascending));
        criteria.where(cBuilder.equal(root.get(Product_.category), category));

        TypedQuery<Product> query = getEm().createQuery(criteria);
        query.setFirstResult(startRecord);
        query.setMaxResults(pageSize);

        List<Product> results = query.getResultList();
        return results;
    }
	
	@Override
	public Long getCount(Category category) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<Long> criteria = cBuilder.createQuery(Long.class);
		Root<Product> root = criteria.from(Product.class);

		criteria.select(cBuilder.count(root));
		criteria.where(cBuilder.equal(root.get(Product_.category), category));
		
		TypedQuery<Long> query = getEm().createQuery(criteria);
		return query.getSingleResult();
	}
	
	@Override
    public List<Product> getSortedAllProduct(SingularAttribute<Product, ?> attr, boolean ascending,
    		int startRecord, int pageSize, Category category, String company) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Product> criteria = cBuilder.createQuery(Product.class);
        Root<Product> root = criteria.from(Product.class);

        criteria.select(root);
        criteria.orderBy(new OrderImpl(root.get(attr), ascending));
        criteria.where(cBuilder.and(cBuilder.equal(root.get(Product_.category), category)),
        		cBuilder.equal(root.get(Product_.company), company));

        TypedQuery<Product> query = getEm().createQuery(criteria);
        query.setFirstResult(startRecord);
        query.setMaxResults(pageSize);

        List<Product> results = query.getResultList();
        return results;
    }
	
	@Override
	public Long getCount(Category category,String company) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<Long> criteria = cBuilder.createQuery(Long.class);
		Root<Product> root = criteria.from(Product.class);

		criteria.select(cBuilder.count(root));
		criteria.where(cBuilder.and(cBuilder.equal(root.get(Product_.category), category)),
        		cBuilder.equal(root.get(Product_.company), company));
		
		TypedQuery<Long> query = getEm().createQuery(criteria);
		return query.getSingleResult();
	}
}
